// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BUFFER_WRITER_H
#define BUFFER_WRITER_H
#include <utility>
#include "cerrno"

#include "MemoryManagement/VmiBuffer.h"

class BufferWriter {
public:
    enum Error : int {
        OK = 0,
        ERROR = 1,
    };

    /**
    * @brief : BufferWriter construtor,init the member variables:m_data m_len m_writePos
    * @param [in]data: first object :the data
                       second object:the length of data
    */
    explicit BufferWriter(std::pair<uint8_t *, size_t> data);

    /**
    * @brief : BufferWriter construtor
    * @param [in]buf: VmiBuffer
    */
    explicit BufferWriter(const VmiBuffer& buf);

    /**
    * @brief : BufferWriter destructor
    */
    virtual ~BufferWriter();

    /**
    * @brief : clear the buffer
    */
    void Clear();

    /**
    * @brief : template overload operator <<
    * @param [in]value: the data to be writed
    * @return : object BufferWriter
    */
    template <typename T> BufferWriter& operator<<(const T value)
    {
        std::pair<const uint8_t *, size_t> data(reinterpret_cast<const uint8_t *>(&value), sizeof(T));
        Append(data);
        return *this;
    };

    /**
    * @brief : overload operator <<
    * @param [in] bufferData: buffer to write
    * @return : object BufferWriter
    */
    BufferWriter& operator<<(VmiBuffer bufferData);

    /**
    * @brief : get the Write position
    * @return : the Write position
    */
    size_t GetWritePosition() const;

    /**
    * @brief : set the Write position and return it
    * @param [in]pos: the Write position
    * @return : the Write position
    */
    size_t SetWritePosition(size_t pos);

    /**
    * @brief : judge if the data address is null
    * @return : true: the data address is null,
                false:the data address is no null,
    */
    bool IsDataNull() const;

    /**
    * @brief : get the length of data which is waiting to write
    * @return : the length
    */
    size_t Length() const;

    /**
    * @brief : get the length of remaining data
    * @return : the length of remaining data
    */
    size_t Remain() const;

    /**
    * @brief : template converts uint8_t
   * @param [in]src: first object:the data to be writed
                     second object:the length of data
    */
    template <class T> void Append(std::pair<const T*, size_t> src) const;

    /**
    * @brief : append the data
    * @param [in]src: first object:the data to be writed
                      second object:the length of data
    */
    void Append(std::pair<const uint8_t*, size_t> src);

    /**
    * @brief : skip data of specified length
    * @param [in]src: the specified length
    */
    void Skip(size_t skip);

    /**
    * @brief : get error number
    * @return : error number
    */
    int GetErrorNumber() const;

    /**
     * @brief : reset error number
     */
    void ResetErrorNumber();

protected:
    uint8_t* m_data = nullptr;
    size_t m_len = 0;
    size_t m_writePos = 0;
    int m_errno = OK;
};

#endif
